using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Data.Common;
using System.Text;
using System.Collections;
using System.Web.UI.HtmlControls;
using System.Globalization;
using System.Web.Script.Services;
using System.Web.Services;
using System.Xml;

/// <summary>
/// A page which shows graphs detailing the completion of resources assigned to an application
/// </summary>
public partial class ResourceSummary : System.Web.UI.Page
{
    private Database db;

    /// <summary>
    /// Displays available applications
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void Page_Load(object sender, EventArgs e)
    {
        pnlError.Visible = false;
        lblNothingSelected.Visible = false;
        if(!Page.IsPostBack) {
            if(db == null || !db.Connected) {
                db = new Database();
                db.OpenConnection();
            }
            using(Database.Command cmd = db.CreateCommand()) {
                cmd.CommandText = "SELECT id, displayname FROM " + db.TablePrefix + "applications ORDER BY name ASC";
                Database.DataAdapter adapter = new Database.DataAdapter(cmd);
                DataSet ds = new DataSet();
                adapter.Fill(ds);
                chlApplication.DataSource = ds;
                chlApplication.DataValueField = "id";
                chlApplication.DataTextField = "displayname";
                chlApplication.DataBind();
                if(chlApplication.Items.Count > 0) {
                    mltMain.ActiveViewIndex = 1;
                }
            }
        }
    }

    /// <summary>
    /// Closes the database connection when rendering is done.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void Page_Unload(object sender, EventArgs e) {
        if(db != null && db.Connected) {
            db.CloseConnection();
        }
    }
        
    /// <summary>
    /// 
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnShowSummary_Click(object sender, EventArgs e) {
        if(chlApplication.SelectedIndex < 0) {
            lblNothingSelected.Visible = true;
            return;
        }
        lstErrors.Items.Clear();
        if(db == null || !db.Connected) {
            db = new Database();
            db.OpenConnection();
        }
        using(Database.Command cmd = db.CreateCommand()) {
            cmd.AddParameterWithValue("@app", "");
            cmd.AddParameterWithValue("@abbrev", "");
            foreach(ListItem itm in chlApplication.Items) {
                if(itm.Selected) {
                    string applicationId = itm.Value;
                    cmd.CommandText = "SELECT defaultLanguage, languages FROM " + db.TablePrefix + "applications WHERE id = @app";
                    cmd.Parameters["@app"].Value = applicationId;
                    try {
                        DbDataReader reader = cmd.ExecuteReader();
                        PlaceHolder plcSummary = new PlaceHolder();
                        plcDynamic.Controls.Add(plcSummary);
                        plcSummary.Controls.Add(new LiteralControl("<h2>"+string.Format("Resource Summary for {0}", itm.Text)+"</h2>"));
                        plcSummary.Controls.Add(new LiteralControl("<h3>Bundles</h3>"));
                        BulletedList lstBundles = new BulletedList();
                        plcSummary.Controls.Add(lstBundles);
                        string[] langCodes = null;
                        string defaultLang = null;
                        while(reader.Read()) {
                            langCodes = reader["languages"].ToString().Split(',');
                            defaultLang = reader["defaultlanguage"].ToString();
                        }
                        reader.Close();
                        StringBuilder sqlBuffer = new StringBuilder("SELECT name, (SELECT COUNT(bundle) FROM ").Append(db.TablePrefix).Append("elements AS e WHERE e.bundle = b.id) AS number FROM ")
                                      .Append(db.TablePrefix).Append("bundles AS b WHERE application = @app");
                        cmd.CommandText = sqlBuffer.ToString();
                        sqlBuffer.Remove(0, sqlBuffer.Length);
                        reader = cmd.ExecuteReader();
                        lstBundles.Items.Clear();
                        string bundleFormat = "{0} ({1} element{2})";
                        while(reader.Read()) {
                            try {
                                int numElements = reader.GetInt32(1);
                                lstBundles.Items.Add(string.Format(bundleFormat, reader["name"].ToString(), numElements, numElements == 1 ? "" : "s"));
                            } catch {
                                lstErrors.Items.Add("Could not read bundle:" + reader[0].ToString());
                            }
                        }
                        reader.Close();
                        sqlBuffer.Append("SELECT COUNT(language) FROM ").Append(db.TablePrefix).Append("elements AS e LEFT JOIN ").Append(db.TablePrefix).Append("resources AS r ON e.resourceid = r.resourceid WHERE language = @abbrev AND applicationid = @app");
                        cmd.CommandText = sqlBuffer.ToString();
                        cmd.Parameters["@abbrev"].Value = defaultLang;
                        double totalElements = 0;
                        try {
                            totalElements = double.Parse(cmd.ExecuteScalar().ToString());
                        } catch {
                            throw new Exception("Error reading the total number of elements");
                        }
                        if(lstBundles.Items.Count > 1) {
                            plcSummary.Controls.Add(new LiteralControl("<p>" + string.Format("{0} elements overall", totalElements) + "</p>"));
                        }
                        List<LanguageCompletion> completionMap = new List<LanguageCompletion>();
                        // the map is sorted by the english name of the languages it contains, but the abbreviation is needed to find the flag image
                        try {
                            CultureInfo defaultCulture = CultureInfo.GetCultureInfo(defaultLang);
                            completionMap.Add(new LanguageCompletion(defaultCulture.EnglishName, Utils.GetISO3166(defaultCulture), "100"));
                        } catch {
                            completionMap.Add(new LanguageCompletion(defaultLang, defaultLang, "100"));
                        }
                        foreach(string abbrev in langCodes) {
                            if(abbrev == defaultLang) {
                                continue; // already added before the start
                            }
                            cmd.Parameters["@abbrev"].Value = abbrev;
                            try {
                                CultureInfo info = CultureInfo.GetCultureInfo(abbrev);
                                double numTranslations = double.Parse(cmd.ExecuteScalar().ToString());
                                int completionPercentage = (int)Math.Round((numTranslations / totalElements) * 100.0, 0);
                                completionMap.Add(new LanguageCompletion(info.EnglishName, Utils.GetISO3166(info), numTranslations > 0 ? completionPercentage > 100 ? "100" : completionPercentage.ToString() : "0")); // famfamfam's flags comply with ISO3166 thankfully
                            } catch(Exception ex) {
                                completionMap.Add(new LanguageCompletion(abbrev, abbrev, "0"));
                                lstErrors.Items.Add("Could not parse culture for " + abbrev + ": " + ex.Message);
                            }
                        }

                        completionMap.Sort(new Comparison<LanguageCompletion>(delegate(LanguageCompletion a, LanguageCompletion b) {
                            return a.EnglishName.CompareTo(b.EnglishName);
                        }));
                        StringBuilder graphBuffer = new StringBuilder();
                        graphBuffer.Append("<h3>Translation Completion</h3>\n<div class=\"translations\">");
                        foreach(LanguageCompletion language in completionMap) {
                            graphBuffer.AppendLine("  <div class=\"row\">")
                                       .AppendLine("    <div class=\"translationName\">")
                                       .AppendFormat("      {1}<img height=\"11\" width=\"16\" src=\"{0}\" alt=\"{1}\" />\n", ResolveUrl("~/images/flags/" + language.Image + ".png"), language.EnglishName)
                                       .AppendLine("    </div>\n    <div class=\"graph\">")
                                       .AppendFormat("      <strong class=\"bar\" style=\"width:{0}%;\">{0}%</strong>\n", language.Completion)
                                       .AppendLine("    </div>")
                                       .AppendLine("  </div>");
                        }
                        graphBuffer.AppendLine("</div>");
                        Literal litGraph = new Literal();
                        litGraph.Text = graphBuffer.ToString();
                        plcSummary.Controls.Add(litGraph);
                    } catch(Exception ex) {
                        lstErrors.Items.Add(ex.Message);
                    }
                    if(lstErrors.Items.Count > 0) {
                        pnlError.Visible = true;
                    }
                    mltMain.ActiveViewIndex = 2;
                }
            }
            /* //todo: summary of all applications/average completion?
             * if(plcDynamic.Controls.Count > 1) {
                StringBuilder sqlBuffer = new StringBuilder("SELECT COUNT(language) FROM ").Append(db.TablePrefix).Append("elements AS e LEFT JOIN ").Append(db.TablePrefix).Append("resources AS r ON e.resourceid = r.resourceid WHERE language = @abbrev"+db.GenerateInClause("applicationid", ,true));
                cmd.CommandText = sqlBuffer.ToString();
                cmd.Parameters["@abbrev"].Value = defaultLang;
            }*/
        }
    }

    private class LanguageCompletion {
        public string EnglishName { get; set; }
        public string Image { get; set; }
        public string Completion { get; set; }
        public LanguageCompletion(string englishName, string image, string completion) {
            this.EnglishName = englishName;
            this.Image = image;
            this.Completion = completion;
        }
    }
}
